package org.apache.rocketmq.store.index;



import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;


/**
 * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
 * @author：陈清风扬，个人微信号：chenqingfengyangjj。
 * @date:2025/7/14
 * @方法描述：封装索引文件的头部信息的类
 */
public class IndexHeader {

    //文件头大小
    public static final int INDEX_HEADER_SIZE = 40;

    //开始存储消息的时间戳在文件缓冲区中的写入和读取位置
    private static int beginTimestampIndex = 0;

    //结束存储消息的时间戳在文件缓冲区中的写入和读取位置
    private static int endTimestampIndex = 8;

    //开始存储消息的物理偏移量在文件缓冲区中的写入和读取位置
    private static int beginPhyoffsetIndex = 16;

    //结束存储消息的物理偏移量在文件缓冲区中的写入和读取位置
    private static int endPhyoffsetIndex = 24;

    //哈希槽使用数量在文件缓冲区中的写入和读取位置
    private static int hashSlotcountIndex = 32;

    //索引文件存储的索引条目在文件缓冲区中的写入和读取位置
    private static int indexCountIndex = 36;

    //内存映射文件缓冲区
    private final ByteBuffer byteBuffer;

    private final AtomicLong beginTimestamp = new AtomicLong(0);

    private final AtomicLong endTimestamp = new AtomicLong(0);

    private final AtomicLong beginPhyOffset = new AtomicLong(0);

    private final AtomicLong endPhyOffset = new AtomicLong(0);

    private final AtomicInteger hashSlotCount = new AtomicInteger(0);

    private final AtomicInteger indexCount = new AtomicInteger(1);

    public IndexHeader(final ByteBuffer byteBuffer) {
        this.byteBuffer = byteBuffer;
    }


    public void load() {

        this.beginTimestamp.set(byteBuffer.getLong(beginTimestampIndex));
        this.endTimestamp.set(byteBuffer.getLong(endTimestampIndex));
        this.beginPhyOffset.set(byteBuffer.getLong(beginPhyoffsetIndex));
        this.endPhyOffset.set(byteBuffer.getLong(endPhyoffsetIndex));
        this.hashSlotCount.set(byteBuffer.getInt(hashSlotcountIndex));
        this.indexCount.set(byteBuffer.getInt(indexCountIndex));
        if (this.indexCount.get() <= 0) {
            this.indexCount.set(1);
        }
    }


    public void updateByteBuffer() {

        this.byteBuffer.putLong(beginTimestampIndex, this.beginTimestamp.get());
        this.byteBuffer.putLong(endTimestampIndex, this.endTimestamp.get());
        this.byteBuffer.putLong(beginPhyoffsetIndex, this.beginPhyOffset.get());
        this.byteBuffer.putLong(endPhyoffsetIndex, this.endPhyOffset.get());
        this.byteBuffer.putInt(hashSlotcountIndex, this.hashSlotCount.get());
        this.byteBuffer.putInt(indexCountIndex, this.indexCount.get());
    }


    public long getBeginTimestamp() {
        return beginTimestamp.get();
    }


    public void setBeginTimestamp(long beginTimestamp) {
        this.beginTimestamp.set(beginTimestamp);
        this.byteBuffer.putLong(beginTimestampIndex, beginTimestamp);
    }


    public long getEndTimestamp() {
        return endTimestamp.get();
    }


    public void setEndTimestamp(long endTimestamp) {
        this.endTimestamp.set(endTimestamp);
        this.byteBuffer.putLong(endTimestampIndex, endTimestamp);
    }


    public long getBeginPhyOffset() {
        return beginPhyOffset.get();
    }


    public void setBeginPhyOffset(long beginPhyOffset) {
        this.beginPhyOffset.set(beginPhyOffset);
        this.byteBuffer.putLong(beginPhyoffsetIndex, beginPhyOffset);
    }


    public long getEndPhyOffset() {
        return endPhyOffset.get();
    }


    public void setEndPhyOffset(long endPhyOffset) {
        this.endPhyOffset.set(endPhyOffset);
        this.byteBuffer.putLong(endPhyoffsetIndex, endPhyOffset);
    }


    public AtomicInteger getHashSlotCount() {
        return hashSlotCount;
    }


    public void incHashSlotCount() {
        int value = this.hashSlotCount.incrementAndGet();
        this.byteBuffer.putInt(hashSlotcountIndex, value);
    }


    public int getIndexCount() {
        return indexCount.get();
    }


    public void incIndexCount() {
        int value = this.indexCount.incrementAndGet();
        this.byteBuffer.putInt(indexCountIndex, value);
    }
}

